/*
 * Copyright (c) 2011 Jean-Marc Perronne
 * Ensisa, 12 rue des Freres Lumieres, F-68093 Mulhouse cedex
 * All rights reserved.
 *
 * The copyright of this software is owned by Werner Randelshofer. 
 * You may not use, copy or modify this software, except in  
 * accordance with the license agreement you entered into with  
 * Jean-Marc Perronne. For details see accompanying license terms. 
 */

package fr.uha.ensisa.jmp.drone.input.progressive.keyboard;

import java.awt.AWTEvent;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import fr.uha.ensisa.jmp.drone.at_commands.AtCommand;
import fr.uha.ensisa.jmp.drone.at_commands.AtCommands;
import fr.uha.ensisa.jmp.drone.at_commands.AtPcmCommand;
import fr.uha.ensisa.jmp.drone.input.progressive.FlightInputs;


public class KeyboardHandler implements FlightInputs, KeyListener
{
	private static AtPcmCommand pcmCommand = new AtPcmCommand();
	private static final int DEFAULT_SENSIBILITY = 2;
	
	private boolean  keys[] = {false, false, false, false, false, false, false, false};
	private enum keyBinding{left,right,up,down,s,q};
	
	private int lr, fb, ud, rlr;
	private int olr, ofb, oud, orlr;
	private boolean takeoff, land;
	
	private int sensibility;
	private KeyboardAdapter inputAdapter;
	
	public KeyboardHandler()
	{
		this(DEFAULT_SENSIBILITY);
	}

	public KeyboardHandler(int sensibility)
	{
		this.addKeyListener(this);
		this.sensibility = sensibility;
		this.inputAdapter = new KeyboardAdapter();
	}
	private void addKeyListener(final KeyListener l)
	{
		Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener() {
	        public void eventDispatched(AWTEvent event)
	        {
	              KeyEvent e = (KeyEvent)event;	              
	              switch(e.getID())
	              {
	            	  case KeyEvent.KEY_RELEASED: l.keyReleased(e); break;
	            	  case KeyEvent.KEY_PRESSED: l.keyPressed(e); break;
	            	  case KeyEvent.KEY_TYPED: l.keyTyped(e);break;
	              }
		        }
	     }, AWTEvent.KEY_EVENT_MASK);	
	}

	private void resetFlightsCommands()
	{
		this.lr=0;
		this.fb=0;
		this.ud=0;
		this.rlr=0;
	}
	
	private void resetLandTakeOffCommands()
	{
		this.land=false;
		this.takeoff=false;
	}
	
	private void increaseSensibility()
	{
		int res = this.sensibility + 1;
		this.sensibility = (res <=10)? res: 10;
	}

	private void decreaseSensibility()
	{
		int res = this.sensibility -1;
		this.sensibility= (res >= 1)? res: 1;
	}

	public int sensibility()
	{
		return this.sensibility;
	}
	
	private int increaseValue(int v, int sensibility)
	{
		if (v < 0) v=0;
		int res = v + sensibility;
		return (res <=100)? res: 100;
	}
	
	private int decreaseValue(int v, int sensibility)
	{
		if (v > 0 ) v=0;
		int res = v - sensibility;
		return (res >=-100)? res: -100;
	}
	
	@Override
	public void initialize()
	{
		this.resetLandTakeOffCommands();
		this.resetFlightsCommands(); 
	}

	@Override
	public AtCommand command()
	{	
		AtCommand res = null;

		if(this.land)
		{
			//System.out.println("land");
			this.resetLandTakeOffCommands();
			return AtCommands.LAND;
		}
		
		if(this.takeoff)
		{
			//System.out.println("take off");
			this.resetLandTakeOffCommands();
			return AtCommands.TAKE_OFF;
		}
		
		if ((lr != this.olr) || (fb != this.ofb) || (ud != oud) || (rlr != orlr))
		{
			float clr = this.inputAdapter.adaptLeftRight(this.lr);
			float cfb = this.inputAdapter.adaptFrontBack(this.fb);
			float cud = this.inputAdapter.adaptUpDown(this.ud);
			float crlr = this.inputAdapter.adaptRotateLeftRight(this.rlr);

			//System.out.println("lr("+ clr + ") fb("+ cfb + ") ud("+ cud+ ") rlr("+ crlr + ")");
			KeyboardHandler.pcmCommand.param(true, clr,cfb, cud, crlr);	
			res =  KeyboardHandler.pcmCommand;
		}

		this.olr = lr;
		this.ofb = fb;
		this.oud = ud;
		this.orlr = rlr;
		
		return res;
	}

	@Override
	public boolean failed()
	{
		return false;
	}

	@Override
	public void keyPressed(KeyEvent e)
	{
		//if (e.isShiftDown()) this.keys[keyBinding.shift.ordinal()] = true;;
		final int key = e.getKeyCode();
				
		switch(key)
		{
	   	    case KeyEvent.VK_LEFT:
	   	    	this.keys[keyBinding.left.ordinal()] = true;
	     	    break;
    	    	
			case KeyEvent.VK_RIGHT:
	   	    	this.keys[keyBinding.right.ordinal()] = true;
	   	    	break;
    	    	
			case KeyEvent.VK_UP:
	   	    	this.keys[keyBinding.up.ordinal()] = true;
				break;
				
			case KeyEvent.VK_DOWN:
	   	    	this.keys[keyBinding.down.ordinal()] = true;
				break;
				    	    
    	    case KeyEvent.VK_S :
	   	    	this.keys[keyBinding.s.ordinal()] = true;
    	    	break;
    	    
    	    case KeyEvent.VK_Q :
	   	    	this.keys[keyBinding.q.ordinal()] = true;
    	    	break;

    	    case KeyEvent.VK_SPACE:
	   	    	this.land = false;
	   	    	this.takeoff = true;
    	    	return;
    	    	
    	    case KeyEvent.VK_ESCAPE :
	   	    	this.land = true;
	   	    	this.takeoff = false;
	   	    	return;
    	       	    
    	    default:
    	    	return;
		}
		this.processKey();
	}

	@Override
	public void keyReleased(KeyEvent e)
	{			
		//if (e.isShiftDown()) this.keys[keyBinding.shift.ordinal()] = false;
		final int key = e.getKeyCode();
		
		switch(key)
		{
	   	    case KeyEvent.VK_LEFT:
	   	    	this.keys[keyBinding.left.ordinal()] = false;
     	    	break;
    	    	
			case KeyEvent.VK_RIGHT:
	   	    	this.keys[keyBinding.right.ordinal()] = false;
	   	    	break;
    	    	
			case KeyEvent.VK_UP:
	   	    	this.keys[keyBinding.up.ordinal()] = false;
				break;
				
			case KeyEvent.VK_DOWN:
	   	    	this.keys[keyBinding.down.ordinal()] = false;
				break;
				    	    
    	    case KeyEvent.VK_S :
	   	    	this.keys[keyBinding.s.ordinal()] = false;
	   	    	break;
       	    
    	    case KeyEvent.VK_Q :
	   	    	this.keys[keyBinding.q.ordinal()] = false;
	   	    	break;
   	    
    	    default:
    	    	return;
		}
		this.processKey();
	}

	@Override
	public void keyTyped(KeyEvent e)
	{	
	}

	private void processKey()
	{
		final boolean select = this.keys[keyBinding.q.ordinal()];
		
		if (this.keys[keyBinding.left.ordinal()])
		{
			//System.out.print("<-");
			if (select) this.rlr = this.decreaseValue(this.rlr, sensibility);
			else this.lr = this.decreaseValue(this.lr, sensibility);
		}
		else if (this.keys[keyBinding.right.ordinal()])
		{
			//System.out.print("->");
   	    	if (select) this.rlr = this.increaseValue(this.rlr, sensibility);
   	    	else this.lr = this.increaseValue(this.lr, sensibility);
		}
		else
		{
			this.rlr = 0;
			this.lr = 0;
		}

		if (this.keys[keyBinding.up.ordinal()])
		{
			//System.out.print("^");
			if (select) this.ud = this.increaseValue(this.ud, sensibility);
			else this.fb = this.decreaseValue(this.fb, sensibility);
		}
		else if (this.keys[keyBinding.down.ordinal()])
		{
			//System.out.print("~^");
			if (select) this.ud = this.decreaseValue(this.ud, sensibility);
			else this.fb = this.increaseValue(this.fb, sensibility);
		}
		else
		{
			this.ud = 0;
			this.fb = 0;
		}
		
		if (this.keys[keyBinding.s.ordinal()])
		{
			//System.out.print("s");
			if (select) this.decreaseSensibility();
			else this.increaseSensibility();
		}
		
		//System.out.println();
	}
/*	
	public static void main(String args[]) throws InterruptedException
	{
		KeyboardHandler kh = new KeyboardHandler();
		JFrame test = new JFrame();
		test.pack();
		test.setVisible(true);
		while(true)
		{
			kh.command();
			Thread.sleep(20);
		}
	}
	*/
}
